package top.lidee.module.aggregat.service.Impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.diagnosis.DiagnosisUtils;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.file.IOUtils;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import lombok.extern.slf4j.Slf4j;
import org.iherus.codegen.qrcode.SimpleQrcodeGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import top.lidee.common.bean.AliPayResource;
import top.lidee.common.enums.AlipayProductEnum;
import top.lidee.common.enums.PayTypeEnum;
import top.lidee.common.param.TogetherPayParam;
import top.lidee.common.service.*;
import top.lidee.common.service.twice.applet.MtStoreCateService;
import top.lidee.framework.constant.RedisConstant;
import top.lidee.framework.web.ResponseObject;
import top.lidee.module.aggregat.domain.AccessAliagent;
import top.lidee.module.aggregat.service.ClientAggregatService;
import top.lidee.module.utils.Base64Utils;
import top.lidee.repository.model.MtAliBankAccount;
import top.lidee.repository.model.MtAliProductApplyForLog;
import top.lidee.repository.model.MtAlipayAuthBack;
import top.lidee.repository.model.MtStore;
import top.lidee.repository.model.twice.pojo.applet.MtStoreCateEntity;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;


@Slf4j
@Service
public class ClientAggregatServiceImpl implements ClientAggregatService {

    @Autowired
    private AliPayResource aliPayResource;

    @Autowired
    private StoreService service;

    @Autowired
    private AlipayAuthBackService alipayAuthBackService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private MtAliBankAccountService mtAliBankAccountService;

    @Autowired
    private MtAliProductApplyForLogService mtAliProductApplyForLogService;
    /**
     * 微信相关服务接口
     * */
    @Autowired
    private WeixinService weixinService;

    /**
     * 支付宝相关接口
     * */
    @Autowired
    private AlipayService alipayService;

    //店铺主营行业分类表
    @Autowired
    private MtStoreCateService mtStoreCateService;

    public AlipayClient getAlipayClient() {
        AlipayClient alipayClient = new DefaultAlipayClient(aliPayResource.getGatewayUrl(), aliPayResource.getAppId(), aliPayResource.getMerchantPrivateKey(), "json", aliPayResource.getCharset(), aliPayResource.getAlipayPublicKey(), aliPayResource.getSignType());
        return alipayClient;
    }

    /**
     * 支付宝 代理开通当面付产品
     * */
    @Override
    public ResponseObject aliOpenFacetoface(Integer storeId, String userId) throws AlipayApiException {
        MtAliBankAccount aliBankAccount = mtAliBankAccountService.getByStoreId(storeId);//查询支付宝账户结算表
        if (aliBankAccount == null) {
            log.error("未收录该店铺的支付宝账号，storeID-{}", storeId);
            return new ResponseObject(500, "未收录该店铺storeid为" + storeId + "的支付宝账号", null);
        }
        AlipayClient alipayClient = getAlipayClient();
        /**
         * 开启事务
         * */
        AlipayOpenAgentCreateModel agentCreateModel = new AlipayOpenAgentCreateModel();
        agentCreateModel.setAccount(userId);
        ContactModel contactInfo = new ContactModel();//商户联系人信息，包含联系人名称、手机、邮箱信息。联系人信息将用于接受签约后的重要通知
        contactInfo.setContactMobile(aliBankAccount.getContactMobile());
        contactInfo.setContactName(aliBankAccount.getContactName());
        agentCreateModel.setContactInfo(contactInfo);
        AlipayOpenAgentCreateRequest createRequest = new AlipayOpenAgentCreateRequest();
        createRequest.setBizModel(agentCreateModel);
        AlipayOpenAgentCreateResponse createResponse = alipayClient.execute(createRequest);
        JSONObject creatJO = JSONObject.parseObject(createResponse.getBody());

        if (!createResponse.isSuccess() || StrUtil.isBlank(createResponse.getBody())) {
            String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(createResponse);
            log.error("开启事务调用失败-msg{}-sub_code{}-sub_msg{}-诊断链接：{}", creatJO.getString("msg"), creatJO.getString("sub_code"), creatJO.getString("sub_msg"), diagnosisUrl);
            return new ResponseObject(500, creatJO.getString("sub_msg"), null);
        }
        log.info("开启事务调用成功-{}", JSON.toJSONString(JSONObject.toJSON(createResponse)));

        String batchNo = createResponse.getBatchNo();
        MtStore store = service.getById(storeId);
        if (Objects.isNull(store) || Objects.isNull(store.getCateId())) {
            return new ResponseObject(500, "id为" + storeId + "店铺不存在", null);
        }
        MtStoreCateEntity storeCate = mtStoreCateService.getById(store.getCateId());
        if (Objects.isNull(storeCate) || Objects.isNull(storeCate.getSecondaryCateCode())) {
            return new ResponseObject(500, "id为" + storeId + "店铺对应的经营了类目不存在", null);
        }
        /**
         * 代签约当面付产品接口
         * */
        AlipayOpenAgentFacetofaceSignRequest request = new AlipayOpenAgentFacetofaceSignRequest();
        request.setMccCode(storeCate.getFirstCateCode() + "_" + storeCate.getSecondaryCateCode());
        request.setBatchNo(batchNo);
        //特殊资质企业
//        if(判断){
//            // 设置企业特殊资质图片
//            FileItem spImg = new FileItem("企业特殊资质图片 本地文件的绝对路径");
//            request.setSpecialLicensePic(spImg);
//        }
        request.setSignAndAuth(true);//签约后自动进行授权操作
        request.setRate(aliBankAccount.getRate());//手续费率 0.38~0.6%
//        FileItem blImg = new FileItem(store.getLicense());
//        request.setBusinessLicensePic(blImg);
//        FileItem spImg = new FileItem(store.getInteriorUrl());//内景
//        request.setShopScenePic(spImg);
//        FileItem sbImg = new FileItem(store.getDoorPhotographUrl());//门头照片
//        request.setShopSignBoardPic(sbImg);
        request.setShopName(store.getName());
        MtAlipayAuthBack authBack = alipayAuthBackService.getTokenByStoreId(storeId, userId);
        if (StrUtil.isBlank(authBack.getAppAuthToken())) {
            log.error("代签约当面付产品接口调用失败-错误原因:auth_token是空的，商户未成功授权");
            return new ResponseObject(500, "auth_token是空的，商户未成功授权", null);
        }
        request.putOtherTextParam("app_auth_token", authBack.getAppAuthToken());

        AlipayOpenAgentFacetofaceSignResponse faceResponse = alipayClient.execute(request);
        JSONObject faceJO = JSONObject.parseObject(faceResponse.getBody());
        if (!faceResponse.isSuccess() || StrUtil.isBlank(faceResponse.getBody())) {
            String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(faceResponse);
            log.error("代签约当面付产品接口调用失败-msg{}-sub_code{}-sub_msg{}-诊断链接：{}", faceJO.getString("msg"), faceJO.getString("sub_code"), faceJO.getString("sub_msg"), diagnosisUrl);
            return new ResponseObject(500, faceJO.getString("sub_msg"), null);
        }
        log.info("代签约当面付产品接口调用成功-{}", JSON.toJSONString(JSONObject.toJSON(faceResponse)));
        /**
         * 提交事务
         * */
        AlipayOpenAgentConfirmRequest confirmRequest = new AlipayOpenAgentConfirmRequest();
        AlipayOpenAgentConfirmModel model = new AlipayOpenAgentConfirmModel();
        model.setBatchNo(batchNo);
        request.setBizModel(model);
        AlipayOpenAgentConfirmResponse confirmResponse = alipayClient.execute(confirmRequest);
        JSONObject confirmJO = JSONObject.parseObject(confirmResponse.getBody());
        if (!confirmResponse.isSuccess() || StrUtil.isBlank(confirmResponse.getBody())) {
            String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(confirmResponse);
            log.error("提交事务接口调用失败-msg{}-sub_code{}-sub_msg{}-诊断链接：{}", confirmJO.getString("msg"), confirmJO.getString("sub_code"), confirmJO.getString("sub_msg"), diagnosisUrl);
            return new ResponseObject(500, confirmJO.getString("sub_msg"), null);
        }
        MtAliProductApplyForLog applyForLog = new MtAliProductApplyForLog();
        applyForLog.setStoreId(storeId);
        applyForLog.setProductName(AlipayProductEnum.FACE_TO_FACE_PAYMENT.getKey());
        applyForLog.setProductCode(AlipayProductEnum.FACE_TO_FACE_PAYMENT.getValue());
        applyForLog.setProductStatus(AlipayProductEnum.NONE.getValue());
        applyForLog.setUserId(confirmResponse.getUserId());
        applyForLog.setOpenId(confirmResponse.getOpenId());
        applyForLog.setAuthAppId(confirmResponse.getAuthAppId());
        applyForLog.setAppAuthToken(confirmResponse.getAppAuthToken());
        applyForLog.setAppRefreshToken(confirmResponse.getAppRefreshToken());
        applyForLog.setExpiresIn(confirmResponse.getExpiresIn());
        applyForLog.setReExpiresIn(confirmResponse.getReExpiresIn());
        applyForLog.setOrderNo(confirmResponse.getOrderNo());
        applyForLog.setCreateTime(new Date());
        mtAliProductApplyForLogService.addApplyForLog(applyForLog);//新增审核记录
        log.info("提交事务接口调用成功-{}", JSON.toJSONString(JSONObject.toJSON(confirmResponse)));
        return new ResponseObject(200, "代开通当面付开通接口调取完成", confirmJO);
    }

    /**
     * 支付宝代签产品通用接口
     *
     * @param agent
     */
    @Override
    public ResponseObject aliOpenProducts(AccessAliagent agent) throws AlipayApiException {
        MtAliBankAccount aliBankAccount = mtAliBankAccountService.getByStoreId(agent.getStoreId());//查询支付宝账户结算表
        if (StrUtil.isBlank(aliBankAccount.getAlipayNum())) {
            log.error("未收录该店铺的支付宝账号，storeID-{}", agent.getStoreId());
            return new ResponseObject(500, "未收录该店铺storeid为" + agent.getStoreId() + "的支付宝账号", null);
        }
        log.info("当前需要开通的产品代码{}", agent.getProductCode());
        AlipayClient alipayClient = getAlipayClient();
        /**
         * 开启事务
         * */
        AlipayOpenAgentCreateModel agentCreateModel = new AlipayOpenAgentCreateModel();
        agentCreateModel.setAccount(aliBankAccount.getAlipayNum());
        ContactModel contactInfo = new ContactModel();//商户联系人信息，包含联系人名称、手机、邮箱信息。联系人信息将用于接受签约后的重要通知
        contactInfo.setContactMobile(aliBankAccount.getContactMobile());
        contactInfo.setContactName(aliBankAccount.getContactName());
        agentCreateModel.setContactInfo(contactInfo);
        AlipayOpenAgentCreateRequest createRequest = new AlipayOpenAgentCreateRequest();
        createRequest.setBizModel(agentCreateModel);
        AlipayOpenAgentCreateResponse createResponse = alipayClient.execute(createRequest);
        JSONObject creatJO = JSONObject.parseObject(createResponse.getBody());

        if (!createResponse.isSuccess() || StrUtil.isBlank(createResponse.getBody())) {
            String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(createResponse);
            log.error("开启事务调用失败-msg{}-sub_code{}-sub_msg{}-诊断链接：{}", creatJO.getString("msg"), creatJO.getString("sub_code"), creatJO.getString("sub_msg"), diagnosisUrl);
            return new ResponseObject(500, creatJO.getString("sub_msg"), null);
        }
        log.info("开启事务调用失败-{}", JSON.toJSONString(JSONObject.toJSON(createResponse)));

        String batchNo = creatJO.getString("batch_no");
        MtStore store = service.getById(agent.getStoreId());
        if (Objects.isNull(store) || Objects.isNull(store.getCateId())) {
            return new ResponseObject(500, "id为" + agent.getStoreId() + "商户不存在", null);
        }
        MtStoreCateEntity storeCate = mtStoreCateService.getById(store.getCateId());
        if (Objects.isNull(storeCate) || Objects.isNull(storeCate.getSecondaryCateCode())) {
            return new ResponseObject(500, "id为" + agent.getStoreId() + "商户对应的经营了类目不存在", null);
        }
        /**
         * 代签约通用产品接口
         * */
        AlipayOpenAgentCommonSignRequest request = new AlipayOpenAgentCommonSignRequest();
        request.setBatchNo(batchNo);
        request.setMccCode(storeCate.getSecondaryCateCode());
        request.setProdCode(agent.getProductCode());
        AlipayOpenAgentCommonSignResponse commonResponse = alipayClient.execute(request);
        JSONObject commonJO = JSONObject.parseObject(commonResponse.getBody());
        if (!commonResponse.isSuccess() || StrUtil.isBlank(commonResponse.getBody())) {
            String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(commonResponse);
            log.error("代签约当面付产品接口调用失败-msg{}-sub_code{}-sub_msg{}-诊断链接：{}", commonJO.getString("msg"), commonJO.getString("sub_code"), commonJO.getString("sub_msg"), diagnosisUrl);
            return new ResponseObject(500, commonJO.getString("sub_msg"), null);
        }
        log.info("代签约当面付产品接口调用成功-{}", JSON.toJSONString(JSONObject.toJSON(commonResponse)));
        /**
         * 提交事务
         * */
        AlipayOpenAgentConfirmRequest confirmRequest = new AlipayOpenAgentConfirmRequest();
        AlipayOpenAgentConfirmModel model = new AlipayOpenAgentConfirmModel();
        model.setBatchNo(batchNo);
        request.setBizModel(model);
        AlipayOpenAgentConfirmResponse confirmResponse = alipayClient.execute(confirmRequest);
        JSONObject confirmJO = JSONObject.parseObject(confirmResponse.getBody());
        if (!confirmResponse.isSuccess() || StrUtil.isBlank(confirmResponse.getBody())) {
            String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(confirmResponse);
            log.error("提交事务接口调用失败-msg{}-sub_code{}-sub_msg{}-诊断链接：{}", confirmJO.getString("msg"), confirmJO.getString("sub_code"), confirmJO.getString("sub_msg"), diagnosisUrl);
            return new ResponseObject(500, confirmJO.getString("sub_msg"), null);
        }
        log.info("提交事务接口调用成功-{}", JSON.toJSONString(JSONObject.toJSON(confirmResponse)));
        return new ResponseObject(200, "代开通" + agent.getProductCode() + "产品接口调取完成", confirmJO);
    }


    @Override
    public ResponseObject statusQuery(String pid, String productCodes) throws AlipayApiException {
        AlipayClient alipayClient = getAlipayClient();
        AlipayOpenAgentSignstatusQueryRequest request = new AlipayOpenAgentSignstatusQueryRequest();
        AlipayOpenAgentSignstatusQueryModel model = new AlipayOpenAgentSignstatusQueryModel();
        model.setPid(pid);
        List<String> prodeuctList = new ArrayList<>();
        prodeuctList.add(productCodes);
        model.setProductCodes(prodeuctList);
        request.setBizModel(model);
        AlipayOpenAgentSignstatusQueryResponse response = alipayClient.execute(request);
        JSONObject parseObject = JSONObject.parseObject(response.getBody());
        if (!response.isSuccess() || StrUtil.isBlank(response.getBody())) {
            String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
            log.error("查询商户产品签约状态调用失败-msg{}-sub_code{}-sub_msg{}-诊断链接：{}", parseObject.getString("msg"), parseObject.getString("sub_code"), parseObject.getString("sub_msg"), diagnosisUrl);
            log.error("查询的签约商户的账号{}，产品码{}", pid, productCodes);
            return new ResponseObject(500, parseObject.getString("sub_msg"), null);
        }
        return new ResponseObject(200, "查询商户产品的签约状态", parseObject);
    }


    @Override
    public ResponseObject doScanPay(HttpServletRequest request, TogetherPayParam param) throws Exception {
        param.setStoreId(request.getHeader("storeId") == null ? 0 : Integer.parseInt(request.getHeader("storeId")));
        Map<String, Object> result = new HashMap<>();
        if (PayTypeEnum.FULLPAY.getKey().equals(param.getType())) {//直接付
            if (PayTypeEnum.WXPAY.getKey().equals(param.getPayPlant())) {//微信扫码进入
                //todo平台订单处理
                result = weixinService.wxTogetherPay(param);
            } else if (PayTypeEnum.ALIPAY.getKey().equals(param.getPayPlant())) {//支付宝扫码进入
                result = alipayService.aliTogetherPay(param);
            }
        }
        if (PayTypeEnum.DIVIDEPAY.getKey().equals(param.getType())) {//分期付款

        }
        return null;
    }

    /**
     * 聚合支付 微信支付回调接口
     *
     * @param request
     * @return
     * @throws
     */
    @Override
    public void handleWxNotify(HttpServletRequest request) {

    }

    /**
     * 聚合支付 支付宝支付回调接口
     *
     * @return
     * @throws
     */
    @Override
    public void handleAlipayNotify(HttpServletRequest req) throws AlipayApiException {
        log.info("支付宝发送回调消息{}", req.getRequestURI());
        //第三方应用获取商户授权，支付宝调用服务方回调接口
        if (!StrUtil.isBlank(req.getParameter("app_id"))
                && !StrUtil.isBlank(req.getParameter("source"))
                && !StrUtil.isBlank(req.getParameter("state"))
                && !StrUtil.isBlank(req.getParameter("app_auth_code"))
        ) {
            log.info("支付宝发送第三方应用获取商户授权回调接口 app_id:{}  state:{}", req.getParameter("app_id"), req.getParameter("state"));
            String appAuthCode = req.getParameter("app_auth_code");
            String state = req.getParameter("state");
            MtAlipayAuthBack authBack = new MtAlipayAuthBack();
            authBack.setCreateTime(new Date());
            Integer code = (Integer) redisTemplate.opsForValue().get(RedisConstant.STATUS_BASE64 + state);
            if (code == null) {
                //statu回会话失效，需要重新生成
                log.error("缓存失效，支付宝商户需要重新生成再扫码授权 app_id:{}  ", req.getParameter("app_id"));
                String errorLog = "app_id:" + req.getParameter("app_id") + ",会话失效，商户需要重新生成再扫码授权";
                authBack.setErrorLog(errorLog);
                alipayAuthBackService.insert(authBack);
                return;
            }
            //使用appAuthCode获取appAuthToken
            AlipayClient alipayClient = getAlipayClient();
            AlipayOpenAuthTokenAppRequest request = new AlipayOpenAuthTokenAppRequest();
            AlipayOpenAuthTokenAppModel model = new AlipayOpenAuthTokenAppModel();
            model.setGrantType("authorization_code");
            model.setCode(appAuthCode);
            request.setBizModel(model);
            AlipayOpenAuthTokenAppResponse response = alipayClient.execute(request);
            //将商户授权成功后的信息app_auth_token存入DB
            if (!response.isSuccess() || StrUtil.isBlank(response.getBody())) {
                log.error("支付宝 使用appAuthCode获取appAuthToken 失败，原因:{}", response.getMsg());
                authBack.setErrorLog(response.getSubCode() + response.getSubMsg());
                alipayAuthBackService.insert(authBack);
            } else {
                log.info("支付宝 使用appAuthCode获取appAuthToken 成功，appAuthToken:{}", response.getAppAuthToken());
                authBack.setStoreId(code);
                authBack.setUserId(response.getUserId());
                authBack.setAuthAppId(response.getAuthAppId());
                authBack.setAppAuthToken(response.getAppAuthToken());
                authBack.setAppRefreshToken(response.getAppRefreshToken());
                authBack.setReExpiresIn(response.getReExpiresIn());
                alipayAuthBackService.insert(authBack);
            }
            redisTemplate.delete(RedisConstant.STATUS_BASE64 + state);//删除当前status
        }
    }


    @Override
    public ResponseObject createAuthQRcode(Integer code, HttpServletResponse response) throws IOException {
        String uuid = UUID.randomUUID().toString();
        String uuidBase64 = Base64Utils.encode(uuid);
        String key = RedisConstant.STATUS_BASE64 + uuidBase64;
        redisTemplate.opsForValue().set(key, code, 24, TimeUnit.HOURS);

        String fileName = "支付宝二维码.png";
        String saveUrl = "C:\\Users\\30756\\Desktop\\code\\mine\\" + fileName;
        //拼接QRcode参数
        String QRUcode = aliPayResource.getAuthorizeUrl()
                + "?app_id=" + aliPayResource.getAppId()
                + "&state=" + uuidBase64 + "&redirect_uri="
                + URLEncoder.encode(aliPayResource.getNotifyUrl());
        OutputStream out = null;
        try {
            out = new FileOutputStream(saveUrl);
            new SimpleQrcodeGenerator().generate(QRUcode).toStream(out);
        } catch (FileNotFoundException e) {
            return new ResponseObject(500, "二维码生成失败:" + e.getMessage(), null);
        } catch (IOException e) {
            return new ResponseObject(500, "二维码生成失败:" + e.getMessage(), null);
        } finally {
            IOUtils.closeQuietly(out);
        }


        File file = new File(saveUrl);
        if (file.exists()) { //判断文件父目录是否存在
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-Disposition", "attachment;fileName=" + java.net.URLEncoder.encode(fileName, "UTF-8"));
            byte[] buffer = new byte[1024];
            FileInputStream fis = null; //文件输入流
            BufferedInputStream bis = null;
            OutputStream os = null; //输出流
            try {
                os = response.getOutputStream();
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer);
                    i = bis.read(buffer);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                bis.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return new ResponseObject(200, "二维码生成下载成功", saveUrl);
        } else {
            return new ResponseObject(500, "二维码生成下载失败", null);
        }
    }


}
